/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.hokoblurdemo.ability.slice;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Image;
import ohos.agp.components.ProgressBar;
import ohos.agp.components.Slider;
import ohos.agp.components.Text;
import ohos.agp.components.element.PixelMapElement;
import ohos.global.resource.NotExistException;
import ohos.media.image.PixelMap;

import com.example.hokoblurdemo.ability.ResourceTable;
import com.example.hokoblurdemo.ability.Utils.MyValueAnimator;
import com.example.hokoblurdemo.ability.Utils.PixelMapUtil;
import com.hoko.blur.HokoBlur;
import com.hoko.blur.api.IBlurBuild;
import com.hoko.blur.processor.BlurProcessor;
import com.hoko.blur.processorsecond.StackBlurManager;
import com.jaredrummler.materialspinner.MaterialSpinner;

import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @since 2021-08-04
 */
public class MultiBlurAbilitySliceNew  extends AbilitySlice implements Component.ClickedListener {
    private static final float SAMPLE_FACTOR = 8.0f;
    private static final int INIT_RADIUS = 5;
    private static final int[] TEST_IMAGE_RES = {ResourceTable.Media_sample1, ResourceTable.Media_sample2};
    private static final String[] SPINNER_ITEMS_SCHEME = {"RenderScript","OpenGL","Native C/C++","JAVA"};
    private static final String[] SPINNER_ITEMS_ALGORITHM = {"Gaussian","Stack","Box"};
    private int mCurrentImageRes = TEST_IMAGE_RES[0];
    private int index = 0;
    private Image photo;
    private MaterialSpinner spinnerScheme;
    private MaterialSpinner spinnerAlgorithm;
    private Slider mProgressBar;
    private Text mRadiusText;

    private IBlurBuild mBlurBuilder;
    private BlurProcessor mProcessor;

    private PixelMap mInBitmap;

    private int mRadius = INIT_RADIUS;
    private MyValueAnimator mAnimator;
    private MyValueAnimator mRoundAnimator;
    private volatile Future mFuture;
    private ExecutorService mDispatcher = Executors.newSingleThreadExecutor();

    private StackBlurManager _stackBlurManager;
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_multi_blur);
        initView();
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
    private void initView() {
        photo = (Image)findComponentById(ResourceTable.Id_photo);
        photo.setClickedListener(this);
        setImage(mCurrentImageRes);

        spinnerScheme = (MaterialSpinner) findComponentById(ResourceTable.Id_spinnerScheme); // 方案
        spinnerAlgorithm = (MaterialSpinner) findComponentById(ResourceTable.Id_spinnerAlgorithm); // 模糊算法
        spinnerScheme.setItems(SPINNER_ITEMS_SCHEME);
        spinnerAlgorithm.setItems(SPINNER_ITEMS_ALGORITHM);

        mRadiusText = (Text)findComponentById(ResourceTable.Id_blur_radius);

//        mBlurBuilder = HokoBlur.with(this).sampleFactor(SAMPLE_FACTOR);
        _stackBlurManager = new StackBlurManager(PixelMapUtil.getPixelMapFromResource(getContext(),mCurrentImageRes));
        spinnerScheme.setOnItemSelectedListener(new MaterialSpinner.OnItemSelectedListener<String>() {
            @Override
            public void onItemSelected(MaterialSpinner materialSpinner, int i, long l, String o) {
                chooseScheme(i);
                endAnimators();
                mProcessor = mBlurBuilder.processor();
                mProcessor.radius(mRadius);
                updateImage(mRadius);
            }
        });
        spinnerAlgorithm.setOnItemSelectedListener(new MaterialSpinner.OnItemSelectedListener<String>() {
            @Override
            public void onItemSelected(MaterialSpinner materialSpinner, int i, long l, String o) {
                chooseAlgorithm(i);
                endAnimators();
                mProcessor = mBlurBuilder.processor();
                mProcessor.radius(mRadius);
                updateImage(mRadius);
            }
        });
        mProgressBar = (Slider) findComponentById(ResourceTable.Id_radius_seekbar);
        mProgressBar.setValueChangedListener(new Slider.ValueChangedListener() {
            @Override
            public void onProgressUpdated(Slider slider, int i, boolean b) {
                final int radius = (int) (i / 1000f * 25);
                mRadiusText.setText("Blur Radius: " + radius);
//                if(mProcessor ==null){
//                    mProcessor = mBlurBuilder.processor();
//                    mProcessor.radius(mRadius);
//                }
                _stackBlurManager = new StackBlurManager(PixelMapUtil.getPixelMapFromResource(getContext(),mCurrentImageRes));
                updateImage(radius);
            }

            @Override
            public void onTouchStart(Slider slider) {

            }

            @Override
            public void onTouchEnd(Slider slider) {

            }
        });
        Button resetBtn = (Button) findComponentById(ResourceTable.Id_reset_btn);
        resetBtn.setClickedListener(this);
        Button animBtn = (Button)findComponentById(ResourceTable.Id_anim_btn);
        animBtn.setClickedListener(this);

        //add stack new
    }
    private void updateImage(int radius) {
        System.out.println("zhangliang==>"+"updateImage");
        mRadius = radius;
        cancelPreTask();
        mFuture = mDispatcher.submit(new BlurTask(mInBitmap,_stackBlurManager,radius) {
            @Override
            void onBlurSuccess(final PixelMap bitmap) {
                System.out.println("zhangliang==>"+"onBlurSuccess");
                if (!getAbility().isTerminating() && bitmap != null) {
                    getContext().getUITaskDispatcher().asyncDispatch(new Runnable() {
                        @Override
                        public void run() {

                            photo.setPixelMap(bitmap);
                        }
                    });
                }
            }
        });
    }
    private void cancelPreTask() {
        if (mFuture != null && !mFuture.isCancelled() && !mFuture.isDone()) {
            mFuture.cancel(false);
            mFuture = null;
        }
    }

    private void chooseScheme(int schemeInt){
        switch (schemeInt){
            case 0:
                mBlurBuilder.scheme(HokoBlur.SCHEME_RENDER_SCRIPT);
                break;
            case 1:
                mBlurBuilder.scheme(HokoBlur.SCHEME_OPENGL);
                break;
            case 2:
                mBlurBuilder.scheme(HokoBlur.SCHEME_NATIVE);
                break;
            case 3:
                mBlurBuilder.scheme(HokoBlur.SCHEME_JAVA);
                break;
            default:
                break;
        }
    }
    private void chooseAlgorithm(int  algorithmInt){
        switch (algorithmInt){
            case 0:
                mBlurBuilder.mode(HokoBlur.MODE_GAUSSIAN);
                break;
            case 1:
                mBlurBuilder.mode(HokoBlur.MODE_STACK);
                break;
            case 2:
                mBlurBuilder.mode(HokoBlur.MODE_BOX);
                break;
            default:
                break;
        }
    }
    @Override
    public void onClick(Component component) {
        switch (component.getId()){
            case ResourceTable.Id_photo:
                mCurrentImageRes = TEST_IMAGE_RES[++index % TEST_IMAGE_RES.length];
                setImage(mCurrentImageRes);
                _stackBlurManager = new StackBlurManager(PixelMapUtil.getPixelMapFromResource(getContext(),mCurrentImageRes));
                break;
            case ResourceTable.Id_reset_btn:
                endAnimators();
                photo.setPixelMap(mCurrentImageRes);
                mProgressBar.setProgressValue(0);
                break;
            case ResourceTable.Id_anim_btn:
                endAnimators();
                mRoundAnimator = MyValueAnimator.ofFloat(0, 1000);
//                mRoundAnimator.setInterpolator(new LinearInterpolator());
                mRoundAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float v) {
                        mProgressBar.setProgressValue((int)v);
                        final int radius = (int) ((int) v / 1000f * 25);
                        updateImage(radius);
                    }
                });
                mRoundAnimator.setDuration(1000);
                mRoundAnimator.start();
                Thread th = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(1000);
                            getContext().getUITaskDispatcher().asyncDispatch(new Runnable() {
                                @Override
                                public void run() {
                                    endAnimators();
                                    mRoundAnimator = MyValueAnimator.ofFloat(1000, 0);
//                mRoundAnimator.setInterpolator(new LinearInterpolator());
                                    mRoundAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                                        @Override
                                        public void onUpdate(AnimatorValue animatorValue, float v) {
                                            mProgressBar.setProgressValue((int)v);
                                            final int radius = (int) ((int) v / 1000f * 25);
                                            updateImage(radius);
                                        }
                                    });
                                    mRoundAnimator.setDuration(1000);
                                    mRoundAnimator.start();
                                }
                            });
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
                th.start();
                break;
            default:
                break;
        }
    }
    private void setImage(int id) {
        photo.setPixelMap(id);
        mDispatcher.submit(() -> {
            mInBitmap = PixelMapUtil.getPixelMapFromResource(getContext(),id);
            getContext().getUITaskDispatcher().asyncDispatch(new Runnable() {
                @Override
                public void run() {
                    endAnimators();
                    mAnimator = MyValueAnimator.ofFloat(0, mRadius / 25f * 1000);
//                    mAnimator.setInterpolator(new LinearInterpolator());
                    mAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                        @Override
                        public void onUpdate(AnimatorValue animatorValue, float v) {
                            mProgressBar.setProgressValue((Integer) animatorValue.getCurveType());
//                            mSeekBar.setProgress((Integer) animation.getAnimatedValue());
                            updateImage((int) ((Integer) animatorValue.getCurveType() / 1000f * 25f));

                        }
                    } );

                    mAnimator.setDuration(300);
                    mAnimator.start();
                }
            });

        });

    }
    private void endAnimators() {
        if (mAnimator != null && mAnimator.isRunning()) {
            mAnimator.end();
        }
        if (mRoundAnimator != null && mRoundAnimator.isRunning()) {
            mRoundAnimator.end();
        }
    }


    private abstract static class BlurTask implements Runnable {
        private PixelMap bitmap;
        private BlurProcessor blurProcessor;
        private int radius;

        private StackBlurManager _stackBlurManager;

        BlurTask(PixelMap bitmap,StackBlurManager _stackBlurManager,int radius) {
            this.bitmap = bitmap;
            this._stackBlurManager = _stackBlurManager;
            this.radius = radius;
        }


        BlurTask(PixelMap bitmap, BlurProcessor blurProcessor, int radius) {
            this.bitmap = bitmap;
            this.blurProcessor = blurProcessor;
            this.radius = radius;
        }

        @Override
        public void run() {
//            if (bitmap != null && !bitmap.isReleased() && blurProcessor != null) {
//                System.out.println("zhangliang==>"+"run");
//                blurProcessor.radius(radius);
//                onBlurSuccess(blurProcessor.blur(bitmap));
//            }
            System.out.println("zhangliang==>"+bitmap.isReleased());
           if(bitmap != null && !bitmap.isReleased()){
               System.out.println("zhangliang==>"+"run");
               onBlurSuccess(_stackBlurManager.process(radius));
           }
        }

        abstract void onBlurSuccess(PixelMap bitmap);
    }
}

